package evocarcassonne.core.board;

import evocarcassonne.core.board.locations.PawnLocation;
import evocarcassonne.core.board.locations.Position;
import evocarcassonne.core.board.locations.Zone;
import evocarcassonne.core.elements.Element;
import evocarcassonne.core.game.Player;
import evocarcassonne.core.utils.Card;
import evocarcassonne.core.utils.Rot;
import evocarcassonne.core.utils.ZoneType;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Tile {

    //Debug ;
    public int number;
    // Zones of the tile. Used to link cities, roads and fields (3 for a edge)
    Zone[] zones = new Zone[12];
    // Where can be placed a Pawn
    List<PawnLocation> locations = new ArrayList();
    // Is the tile rotated ?
    private int rotation = 0;
    // position on board
    private Position position;
//    private Abbey abbey;

    public Tile(ZoneType NType, ZoneType EType, ZoneType SType, ZoneType WType) {

        // 4 main zones init
        for (int i = 0; i < zones.length; i++) {
            zones[i] = new Zone(i);
        }

        zones[Card.N].setType(NType);
        zones[Card.E].setType(EType);
        zones[Card.S].setType(SType);
        zones[Card.W].setType(WType);

    }

    public Tile() {

        // 4 main zones init
        for (int i = 0; i < zones.length; i++) {
            zones[i] = new Zone(i);
        }
    }

    public void setNorth(ZoneType type) {
        zones[Card.N].setType(type);
    }

    public void setSouth(ZoneType type) {
        zones[Card.S].setType(type);
    }

    public void setWest(ZoneType type) {
        zones[Card.W].setType(type);
    }

    public void setEast(ZoneType type) {
        zones[Card.E].setType(type);
    }

    public void setConnections(int card, Integer conns) {
        zones[card].setConnections(conns);
    }

    public void setCardType(int card, ZoneType value) {

        zones[card].setType(value);

        if (value == ZoneType.ROAD) {
            addDeadEnd(card);
        }
    }

    public Position getPosition() {
        return position;
    }

    public void setPosition(Position position) {
        this.position = position;
    }

    public void rotate0() {
        rotation = Rot.x0;
    }

    public void rotate90() {
        rotation = Rot.x90;
    }

    public void rotate180() {
        rotation = Rot.x180;
    }

    public void rotate270() {
        rotation = Rot.x270;
    }

    public void addLink(int... cards) {

        for (int card1 : cards) {
            for (int card2 : cards) {
                if (card1 != card2) {
                    zones[card1].addLink(zones[card2]);
                }
            }
        }
    }

    public Set<Element> getElements() {

        Set<Element> elements = new HashSet();

        for (Zone zone : zones) {

            if (zone.getElement() != null) {
                elements.add(zone.getElement());
            }
        }

        return elements;
    }

    public Zone getZone(int card) {
        return zones[(card - rotation + zones.length) % zones.length];
    }

    public Zone getReverseZone(int card) {

        if (card == Card.N || card == Card.S || card == Card.E || card == Card.W) {
            return zones[(getZone(card).card + Rot.x180) % zones.length];

        } else {

            int rotatedCard = getZone(card).card;

            int result = 0;
            switch (rotatedCard) {

                case Card.NNW:
                    result = Card.SSW;
                    break;
                case Card.NNE:
                    result = Card.SSE;
                    break;
                case Card.ENE:
                    result = Card.WNW;
                    break;
                case Card.ESE:
                    result = Card.WSW;
                    break;
                case Card.SSE:
                    result = Card.NNE;
                    break;
                case Card.SSW:
                    result = Card.NNW;
                    break;
                case Card.WSW:
                    result = Card.ESE;
                    break;
                case Card.WNW:
                    result = Card.ENE;
                    break;
            }
            return zones[result];

        }
    }

    public void linkAll() {
        addLink(Card.N, Card.S, Card.E, Card.W);
    }

    @Override
    public String toString() {
        return "tile" + number;
    }

    public boolean placePawn(Player player, int card) {
        Element elt = getZone(card).getElement();

        if (elt.canAddPawn()) {

            elt.addPawn(player, getPosition());
            return true;
        }
        return false;
    }

    public boolean centerPlace() {
        return false;
    }

    public void deadEnds(int... cards) {
        for (int i : cards) {
            addDeadEnd(i);
        }
    }

    private void addDeadEnd(int card) {
        zones[card].setDeadEnd(true);
    }

    public void addLink(List<Integer> list) {
        for (int card1 : list) {
            for (int card2 : list) {
                if (card1 != card2) {
                    zones[card1].addLink(zones[card2]);
                }
            }
        }
    }

    public void deadEnds(List<Integer> linkedZones) {
        for (int i : linkedZones) {
            addDeadEnd(i);
        }
    }

    public void addPawnLocations(Integer... pawns) {

        for (Integer card : pawns) {
            zones[card].enablePawn();
        }
    }

    public void addPawnLocations(List<Integer> pawns) {
        for (Integer card : pawns) {
            zones[card].enablePawn();
        }
    }
}
